package com.guodi.model.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.guodi.common.utils.CommonUtil;
import com.guodi.common.utils.DateUtil;
import com.guodi.common.utils.UnitConvertUnit;
import com.guodi.common.utils.UuidUtil;
import com.guodi.map.entity.MapDivision;
import com.guodi.map.feign.IMapClient;
import com.guodi.model.constant.ModelConst;
import com.guodi.model.entity.ApiMdlModelDir;
import com.guodi.model.entity.MdlModel;
import com.guodi.model.entity.MdlModelResult;
import com.guodi.model.entity.MdlModelType;
import com.guodi.model.service.*;
import com.guodi.model.utils.*;
import javax.annotation.Resource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @描述:  模型导出文档 业务类接口
 * @作者:  陈宏成
 * @日期:  2021/2/3 10:52
 **/
@Service
public class MdlModelExportServiceImpl implements IMdlModelExportService {

    @Resource
    private IMdlModelDirService mdlModelDirService;
    @Resource
    private IMdlModelTypeService mdlModelTypeService;
    @Resource
    private IMdlModelService mdlModelService;
    @Resource
    private IMdlModelResultService mdlModelResultService;
    @Resource
    private IMapClient iMapClient;

    private static final String environmentalLoadAssessmentUnit = "万公顷";

    @Resource
    private IIdtIndicatorsDirService iIdtIndicatorsDirService;


    /**
     * @描述: 导出【资源环境承载能力报告动态评估报告.docx】
     * @入参: modelTypeCode 模型体系编码，不能为空
     * @入参: divisionCode 行政区划编码，不能为空
     * @入参: year 年份，不能为空
     * @入参: keyWord 关键字，如果不为空，则根据关键字过滤模型名和模型编码
     * @作者: 陈宏成
     * @日期: 2021/02/04 10:10:10
     **/
    @Override
    public String exportEnvironmentalLoadAssessmentWord ( String modelTypeCode, String divisionCode, String year , String keyWord) throws Exception{
        MapDivision division = iMapClient.mateByCode(divisionCode);
        String divisionText = division == null ? "" : division.getName();
        // 查询模型
        List<ApiMdlModelDir> mdlModelDirs = this.listModelDirs(modelTypeCode, keyWord, year, true);
        List<ApiMdlModelDir> removeItemChildren = new LinkedList<>();
        for(int i = 0; i < mdlModelDirs.size(); i++) {
            ApiMdlModelDir modelDir = mdlModelDirs.get(i);
            if(modelDir.getType() == 1 && modelDir.getName().equals("模型目录")){
                removeItemChildren = modelDir.getChildren();
                mdlModelDirs.remove(i);
                break;
            }
        }
        mdlModelDirs.addAll(removeItemChildren);
        // 生成word临时文件
        StringBuilder stringBuilder = new StringBuilder("");
        // 遍历
        Map<String,Object> dataMap = new HashMap<>();
        dataMap.put("divisionCode",divisionCode);
        dataMap.put("year",year);
        dataMap.put("tableNum",0);
        dataMap.put("levelNum_1",0);
        for(ApiMdlModelDir mdlModelDir : mdlModelDirs) {
            dataMap.put("level",1);
            String htmlStr = this.buildHtmlStrForEnvironmentalLoadAssessmentWord(mdlModelDir, dataMap);
            stringBuilder.append(htmlStr);
        }
        // 处理html图片的预留埋点
        Map<String,String> echartOptions = (Map<String,String>)dataMap.getOrDefault("echartOptions", new HashMap<>());
        this.replaceEchartImgForHtml(echartOptions,stringBuilder);
        // 生成word文档
        Map<String, Object> fieldMap = new HashMap<>(2);
        fieldMap.put("XZQ",divisionText);
        fieldMap.put("NF",year);
        stringBuilder.insert(0,"<style>table,td,th{font-size:12px;border:1px solid grey;padding:5px;width:555px;text-align:center;}p,span,h1,h2,h3,div{font-family:'宋体';}*{font-family:'宋体';}</style>");
        String wordName = this.createWord("【动态评估】资源环境承载动态评估导出.docx", fieldMap, null, null, null, stringBuilder.toString());
        return wordName;
    }

    /**
     * 为【资源环境承载能力报告动态评估报告.docx】构建html内容
     * @入参: modelDir 模型目录，需要是树状结构，不能为空
     * @入参: dataMap 用到的一些上下文数据，例如divisionCode、year、tableNum、levelNum_X
     * @出参: 一个模型的html输出内容
     * @throws IOException
     * @作者: 陈宏成
     * @日期: 2021/02/04
     */
    private String buildHtmlStrForEnvironmentalLoadAssessmentWord(ApiMdlModelDir modelDir, Map<String,Object> dataMap) throws IOException {
        StringBuilder stringBuilder = new StringBuilder("");
        int level = (Integer) dataMap.get("level");
        String divisionCode = (String) dataMap.get("divisionCode");
        // 预先获取好标题序号
        int titleIndex = (Integer) dataMap.get("levelNum_"+level) + 1;
        String titleIndexStr = this.getTitleIndexStr(level,titleIndex);

        if (modelDir.getType() == 1){
            // 如果是目录，递归其子级，如果子级有构建内容，就输出，否则不输出
            if(modelDir.getChildren() != null && !modelDir.getChildren().isEmpty()){
                dataMap.put("levelNum_" + (level+1),0);
                for(ApiMdlModelDir child : modelDir.getChildren()) {
                    dataMap.put("level",level+1);
                    String htmlStr = this.buildHtmlStrForEnvironmentalLoadAssessmentWord(child,dataMap);
                    dataMap.put("level",level);
                    if (StringUtils.hasText(htmlStr)){
                        // 如果子级构建了内容，那么本级也要构建标题
                        stringBuilder.append(htmlStr);
                    }
                }
                dataMap.remove("levelNum_" + (level+1));
                if (stringBuilder.length() > 0){
                    dataMap.put("levelNum_"+level, titleIndex);
                    // 本级的标题
                    stringBuilder.insert(0,"<h"+(level+1)+" style=\"font-family:'宋体';font-size:18px;\">" + titleIndexStr + modelDir.getName()+"</h"+(level+1)+">");
                }
            }
        }else {
            // 如果是模型，要构建自身输出的html内容
            // 解析json
            if (modelDir.getMdlModelResult() == null || !StringUtils.hasText(modelDir.getMdlModelResult().getResult())){
                return "";
            }
            // 解析json数据
            List<Map<String, Object>> listDataFromJson = this.getOneDivisionDataFromModelResult(modelDir.getMdlModelResult().getResult(),divisionCode,true);
            if (listDataFromJson.isEmpty()) {
                // 如果没有这个行政区的数据，直接返回空
                return "";
            }
            // 获取该行政区的数据
            Map<String, Object> divisionData = listDataFromJson.stream().filter(data -> {
                return divisionCode.equals(data.get("divisionCode"));
            }).findFirst().get();
            List<Map<String, String>> divisionDataItems = (List<Map<String, String>>)divisionData.getOrDefault("items",null);

            // 拼接html内容
            String alias = modelDir.getAlias();
            dataMap.put("levelNum_"+level, titleIndex);
            stringBuilder.append("<h"+(level+1)+" style=\"font-family:'宋体';font-size:18px;\">" + titleIndexStr + alias+"</h"+(level+1)+">");
            if (divisionDataItems != null && !divisionDataItems.isEmpty()){
                stringBuilder.append("<p style=\"font-family:'宋体';font-size:18px;text-indent:2em;\">").append("全域").append(alias).append("超载分析中：");
                for(Map<String, String> divisionDataItem : divisionDataItems) {
                    String value = divisionDataItem.get("value");
                    value = String.valueOf(Double.parseDouble(value) / 10000.0);
                    stringBuilder.append(divisionDataItem.get("key")).append("面积为").append(this.holdTwoDecimal(value))
                            .append(environmentalLoadAssessmentUnit);
                    if(divisionDataItem.get("percent") != null){
                        stringBuilder.append("，占比")
                                .append(divisionDataItem.get("percent") != null ? divisionDataItem.get("percent") : "");
                    }
                    stringBuilder.append("；");
                }
                stringBuilder.append("</p>");
            }
            // 构建echart图表
            // 获取option配置文件内容
            String option = (String) dataMap.get( "chartOptionFtlStr" );
            if (!StringUtils.hasText(option)){
                ClassPathResource resource = new ClassPathResource("template/ring_chart_option.ftl" );
                InputStream inputStream = resource.getInputStream();
                option = FileUtil.txt2String(inputStream, "utf-8");
                dataMap.put("chartOptionFtlStr", option);
            }
            List<Map<String, String>> chartNameValueDataList = divisionDataItems.stream().map(item -> {
                Map<String, String> map = new HashMap<>();
                map.put("name", item.get("key"));
                map.put("value", this.holdTwoDecimal(item.get("value")));
                return map;
            }).collect(Collectors.toList());
            List<String> chartNameDataList = divisionDataItems.stream().map(item -> {
                return item.get("key");
            }).collect(Collectors.toList());
            option = option.replace("${titleName}",modelDir.getMdlModel().getName());
            option = option.replace("${nameValueArray}",JSON.toJSONString(chartNameValueDataList));
            option = option.replace("${legendArray}",JSON.toJSONString(chartNameDataList));
            // 将图表结果暂存
            Map<String,String> echartOptions = (Map<String,String>)dataMap.get("echartOptions");
            if (echartOptions == null){
                echartOptions = new HashMap<>();
                dataMap.put("echartOptions",echartOptions);
            }
            echartOptions.put(modelDir.getModelId(), option);
            // 在html中预留埋点，方便后面直接替换
            stringBuilder.append("<img data-id=\"").append(modelDir.getModelId()).append("\">");
            // 处理子行政区部分数据的文字说明
            // 获取子行政区数据
            List<Map<String, Object>> subDivisionDataList = listDataFromJson.stream().filter(data -> {
                return !divisionCode.equals(data.get("divisionCode"));
            }).collect(Collectors.toList());
            if (!subDivisionDataList.isEmpty()){
                // 构建html文本说明
                List<Map<String, String>> subDivisionDataItems;
                // 临时字符串
                // 文本描述html
                StringBuilder subDivisionDescriptionHtml = new StringBuilder("");
                // 表格html
                StringBuilder subDivisionTableHtml = new StringBuilder("");
                // 遍历子行政区数据
                int subDivisionIndex = 1;
                for(Map<String, Object> subDivisionData : subDivisionDataList) {
                    subDivisionDataItems = (List<Map<String, String>>)subDivisionData.getOrDefault("items",null);
                    if (subDivisionDataItems == null || subDivisionDataItems.isEmpty()){
                        continue;
                    }
                    // 每个子行政区数据的数据项都按从大到小排序
                    subDivisionDataItems = subDivisionDataItems.stream().sorted((item1, item2) -> {
                        double value1 = Double.parseDouble(item1.getOrDefault("value", "0.0"));
                        double value2 = Double.parseDouble(item2.getOrDefault("value", "0.0"));
                        return Math.abs(value2 - value1) < 0.000001 ? 0 : value1 > value2 ? -1 : 1;
                    }).collect(Collectors.toList());
                    if (subDivisionDataItems.size() < 2){
                        String value = subDivisionDataItems.get(0).get("value");
                        value = String.valueOf(Double.parseDouble(value) / 10000.0);
                        subDivisionDescriptionHtml.append(subDivisionData.get("divisionText")).append(subDivisionDataItems.get(0).get("key")).append("的面积为")
                                .append(this.holdTwoDecimal(value)).append(environmentalLoadAssessmentUnit).append("；");
                    }else{
                        String maxItemValue = String.valueOf( Double.parseDouble( subDivisionDataItems.get(0).get("value") ) / 10000.0);
                        String minItemValue = String.valueOf( Double.parseDouble( subDivisionDataItems.get(subDivisionDataItems.size() - 1).get("value") ) / 10000.0);
                        subDivisionDescriptionHtml.append(subDivisionData.get("divisionText")).append(subDivisionDataItems.get(0).get("key")).append("的面积最多为")
                                .append(this.holdTwoDecimal(maxItemValue)).append(environmentalLoadAssessmentUnit).append("；")
                                .append(subDivisionData.get("divisionText")).append(subDivisionDataItems.get(subDivisionDataItems.size() - 1).get("key")).append("的面积最少为")
                                .append(this.holdTwoDecimal(minItemValue)).append(environmentalLoadAssessmentUnit).append("；");
                    }
                    // 构建html子行政区划表格
                    for(int i = 0; i < subDivisionDataItems.size(); i++) {
                        Map<String, String> item = subDivisionDataItems.get(i);
                        String value = String.valueOf(Double.parseDouble(item.get("value")) / 10000.0);
                        subDivisionTableHtml.append("<tr>")
                                .append("<td>").append(subDivisionIndex++).append("</td>");
                        if(i == 0){
                            // 只有第一项才需要加这一列，直接合并单元格
                            subDivisionTableHtml.append("<td rowspan = \"").append(subDivisionDataItems.size()).append("\">").append(subDivisionData.get("divisionText")).append("</td>");
                        }
                        subDivisionTableHtml.append("<td>").append(item.get("key")).append("</td>")
                                .append("<td>").append(value).append("</td>")
                                .append("</tr>");
                    }
                }
                if (subDivisionDescriptionHtml.length() > 0){
                    stringBuilder.append("<p style=\"font-family:'宋体';font-size:18px;text-indent:2em;\">").append("下辖行政区中，").append(subDivisionDescriptionHtml.toString()).append("</p>");
                }
                if (subDivisionTableHtml.length() > 0){
                    stringBuilder.append("<table style =\"border-collapse:collapse;border: solid 1px #000;font-family:'宋体';\">")
                            .append("<tr>")
                            .append("<td>序号</td>")
                            .append("<td>行政区划</td>")
                            .append("<td>地类</td>")
                            .append("<td>面积（万公顷）</td>")
                            .append("</tr>")
                            .append(subDivisionTableHtml.toString()).append("</table>");
                }
            }

        }
        return stringBuilder.toString();
    }




    /**
     * @描述: 导出【专题评估报告.docx】
     * @入参: modelTypeCode 模型体系编码，不能为空
     * @入参: divisionCode 行政区划编码，不能为空
     * @入参: year 年份，不能为空
     * @入参: keyWord 关键字，如果不为空，则根据关键字过滤模型名
     * @作者: 陈宏成
     * @日期: 2021/02/03 10:10:10
     **/
    @Override
    public String exportThematicAssessmentWord (String modelTypeCode, String divisionCode, String year , String keyWord) throws Exception {
        MapDivision division = iMapClient.mateByCode(divisionCode);
        String divisionText = division == null ? "" : division.getName();
        // 查询模型
        List<ApiMdlModelDir> mdlModelDirs = this.listModelDirs(modelTypeCode, keyWord, year, true);
        // 生成word临时文件
        StringBuilder stringBuilder = new StringBuilder("");
        // 遍历
        Map<String,Object> dataMap = new HashMap<>();
        dataMap.put("divisionCode",divisionCode);
        dataMap.put("year",year);
        dataMap.put("tableNum",0);
        dataMap.put("levelNum_1",0);
        for(ApiMdlModelDir mdlModelDir : mdlModelDirs) {
            dataMap.put("level",1);
            // 目录名，用于判断就使用哪种echarts图表，现状饼图、协调柱状图
            List<String> modelDirNameList = new LinkedList<>();
            modelDirNameList.add(mdlModelDir.getName());
            dataMap.put("modelDirNameList",modelDirNameList);
            String htmlStr = this.buildHtmlStrForThematicAssessmentWord(mdlModelDir, dataMap);
            stringBuilder.append(htmlStr);
        }
        // 处理html图片的预留埋点
        Map<String,String> echartOptions = (Map<String,String>)dataMap.getOrDefault("echartOptions", new HashMap<>());
        this.replaceEchartImgForHtml(echartOptions,stringBuilder);
        // 生成word文档
        Map<String, Object> fieldMap = new HashMap<>(2);
        fieldMap.put("XZQ",divisionText);
        fieldMap.put("NF",year);
        stringBuilder.insert(0,"<style>table,td,th{font-size:12px;border:1px solid grey;padding:5px;width:555px;text-align:center;}p,span,h1,h2,h3,div{font-family:'宋体';}*{font-family:'宋体';}</style>");
        String wordName = this.createWord("【专题评估】专题评估导出报告.docx", fieldMap, null, null, null, stringBuilder.toString());
        return wordName;
    }

    /**
     * @作者: 林楷 2021/4/29
     * @描述: 导出【资源环境承载能力决策分析报告.docx】
     * @参数: modelTypeCode 模型体系编码
     * @参数: divisionCode 行政区划代码
     * @参数: year 年份
     * @返回: java.lang.String
     */
    @Override
    public String exportDecisionAnalysisReportWord(String modelTypeCode, String divisionCode, Integer year) throws Exception {
        Map<String,Object> dataMap = new HashMap<>();
        MapDivision division = iMapClient.mateByCode(divisionCode);
        String divisionText = division == null ? "" : division.getName();
        Map<String, Object> fieldMap = new HashMap<>(2);
        fieldMap.put("XZQ",divisionText);
        fieldMap.put("NF",year);
        List<ApiMdlModelDir> mdlModelDirs = this.listModelDirs(modelTypeCode, null, year.toString(), true);
        DecimalFormat df = new DecimalFormat("#.##");
        StringBuilder strHtml = new StringBuilder();
        strHtml.append("<h"+(1)+" style=\"font-family:'宋体';font-size:18px;\">一、综合分析</h"+(1)+">");
        for (int i = 0; i < mdlModelDirs.size(); i++) {
            ApiMdlModelDir mdlModelDir = mdlModelDirs.get(i);
            if ("超载类型".equals(mdlModelDir.getName())) {
                strHtml.append("<h" + (2) + " style=\"font-family:'宋体';font-size:18px;\">" + (i + 1) + "、超载综合分析</h" + (2) + ">");
                ApiMdlModelDir chil = mdlModelDir.getChildren().get(0);
                String result = chil.getMdlModelResult().getResult();
                strHtml.append("<p style=\"font-family:'宋体';font-size:18px;text-indent:2em;\">");
                JSONObject resultJson = getModelResultFromDivisionData(result, divisionCode);
                if(resultJson == null) {
                    continue;
                }
                JSONObject dataJson = resultJson.getJSONObject(ModelConst.MODEL_STATISTICAL_STATISTICINFORMATION).getJSONObject(ModelConst.MODEL_VALUE_TYPE_CURRENT);
                JSONObject bczJson = dataJson.getJSONObject("不超载");
                StringBuffer phtml = new StringBuffer();
                if (bczJson != null) {
                    phtml.append("不超载面积为").append(df.format(bczJson.getDouble("Area_Value") / 100000000.0)).append("万公顷，占比")
                            .append(df.format(bczJson.getDouble("Areapercent_Value"))).append("%。");
                }
                JSONObject ljczJson = dataJson.getJSONObject("临界超载");
                if (ljczJson != null) {
                    phtml.append("临界超载面积为").append(df.format(ljczJson.getDouble("Area_Value") / 100000000.0)).append("万公顷，占比")
                            .append(df.format(ljczJson.getDouble("Areapercent_Value"))).append("%。");
                }
                JSONObject czJson = dataJson.getJSONObject("超载");
                if (czJson != null) {
                    phtml.append("超载面积为").append(df.format(czJson.getDouble("Area_Value") / 100000000.0)).append("万公顷，占比")
                            .append(df.format(czJson.getDouble("Areapercent_Value"))).append("%。");
                }
                if (phtml.length() > 0) {
                    phtml.insert(0, divisionText + "资源环境承载能力超载综合分析中");
                }
                strHtml.append(phtml).append("</p>");
                List<Map<String, Object>> listDataFromJson = this.getOneDivisionDataFromModelResult(result, divisionCode, false);
                List<Map<String, String>> items = (List<Map<String, String>>) listDataFromJson.get(0).get("items");
                ClassPathResource resource = new ClassPathResource("template/ring_chart_option.ftl");
                InputStream inputStream = resource.getInputStream();
                String option = FileUtil.txt2String(inputStream, "utf-8");
                List<Map<String, String>> chartNameValueDataList = items.stream().map(item -> {
                    Map<String, String> map = new HashMap<>();
                    map.put("name", item.get("key"));
                    map.put("value", this.holdTwoDecimal(item.get("value")));
                    return map;
                }).collect(Collectors.toList());
                List<String> chartNameDataList = items.stream().map(item -> {
                    return item.get("key");
                }).collect(Collectors.toList());
                JSONObject hj = dataJson.getJSONObject("$合计$");
                option = option.replace("${total}", df.format(hj.getDouble("Area_Value") / 100000000.0));
                option = option.replace("${nameValueArray}", JSON.toJSONString(chartNameValueDataList));
                Map<String, String> echartOptions = (Map<String, String>) dataMap.get("echartOptions");
                if (echartOptions == null) {
                    echartOptions = new HashMap<>();
                    dataMap.put("echartOptions", echartOptions);
                }
                echartOptions.put(chil.getModelId(), option);
                strHtml.append("<img data-id=\"").append(chil.getModelId()).append("\">");
                strHtml.append("<p style=\"font-family:'宋体';font-size:16px;text-indent:2em;text-align:center\">");
                strHtml.append("超载综合分析");
                strHtml.append("</p>");
            }
            if ("预警等级".equals(mdlModelDir.getName())) {
                strHtml.append("<h" + (2) + " style=\"font-family:'宋体';font-size:18px;\">" + (i + 1) + "、预警综合分析</h" + (2) + ">");
                ApiMdlModelDir chil = mdlModelDir.getChildren().get(0);
                String result = chil.getMdlModelResult().getResult();
                strHtml.append("<p style=\"font-family:'宋体';font-size:18px;text-indent:2em;\">");
                JSONObject resultJson = getModelResultFromDivisionData(result, divisionCode);
                if(resultJson == null) {
                    continue;
                }
                JSONObject dataJson = resultJson.getJSONObject(ModelConst.MODEL_STATISTICAL_STATISTICINFORMATION).getJSONObject(ModelConst.MODEL_VALUE_TYPE_CURRENT);
                StringBuffer phtml = new StringBuffer();
                JSONObject green = dataJson.getJSONObject("绿色无警区");
                if (green != null) {
                    phtml.append("绿色无警区面积为").append(df.format(green.getDouble("Area_Value") / 100000000.0)).append("万公顷，占比")
                            .append(df.format(green.getDouble("Areapercent_Value"))).append("%。");
                }
                JSONObject bule = dataJson.getJSONObject("蓝色预警区");
                if (bule != null) {
                    phtml.append("蓝色预警区面积为").append(df.format(bule.getDouble("Area_Value") / 100000000.0)).append("万公顷，占比")
                            .append(df.format(bule.getDouble("Areapercent_Value"))).append("%。");
                }
                JSONObject yellow = dataJson.getJSONObject("黄色预警区");
                if (yellow != null) {
                    phtml.append("黄色预警区面积为").append(df.format(yellow.getDouble("Area_Value") / 100000000.0)).append("万公顷，占比")
                            .append(df.format(yellow.getDouble("Areapercent_Value"))).append("%。");
                }
                JSONObject orange = dataJson.getJSONObject("橙色预警区");
                if (orange != null) {
                    phtml.append("橙色预警区面积为").append(df.format(orange.getDouble("Area_Value") / 100000000.0)).append("万公顷，占比")
                            .append(df.format(orange.getDouble("Areapercent_Value"))).append("%。");
                }
                JSONObject red = dataJson.getJSONObject("红色预警区");
                if (red != null) {
                    phtml.append("红色预警区面积为").append(df.format(red.getDouble("Area_Value") / 100000000.0)).append("万公顷，占比")
                            .append(df.format(red.getDouble("Areapercent_Value"))).append("%。");
                }
                if (phtml.length() > 0) {
                    phtml.insert(0, divisionText + "资源环境承载能力预警综合分析中");
                }
                strHtml.append(phtml).append("</p>");
                List<Map<String, Object>> listDataFromJson = this.getOneDivisionDataFromModelResult(result, divisionCode, false);
                List<Map<String, String>> items = (List<Map<String, String>>) listDataFromJson.get(0).get("items");
                ClassPathResource resource = new ClassPathResource("template/ring_chart_option.ftl");
                InputStream inputStream = resource.getInputStream();
                String option = FileUtil.txt2String(inputStream, "utf-8");
                List<Map<String, String>> chartNameValueDataList = items.stream().map(item -> {
                    Map<String, String> map = new HashMap<>();
                    map.put("name", item.get("key"));
                    map.put("value", this.holdTwoDecimal(item.get("value")));
                    return map;
                }).collect(Collectors.toList());
                List<String> chartNameDataList = items.stream().map(item -> {
                    return item.get("key");
                }).collect(Collectors.toList());
                option = option.replace("${titleName}", chil.getMdlModel().getName());
                option = option.replace("${nameValueArray}", JSON.toJSONString(chartNameValueDataList));
                Map<String, String> echartOptions = (Map<String, String>) dataMap.get("echartOptions");
                if (echartOptions == null) {
                    echartOptions = new HashMap<>();
                    dataMap.put("echartOptions", echartOptions);
                }
                echartOptions.put(chil.getModelId(), option);
                strHtml.append("<img data-id=\"").append(chil.getModelId()).append("\">");
                strHtml.append("<p style=\"font-family:'宋体';font-size:16px;text-indent:2em;text-align:center\">");
                strHtml.append("预警综合分析");
                strHtml.append("</p>");
            }
        }
        strHtml.append("<h"+(1)+" style=\"font-family:'宋体';font-size:18px;\">二、关联因子分析</h"+(1)+">");
        List<ApiMdlModelDir> apiMdlModelDirs = this.listModelDirs("dynamic-evaluate", null, year.toString(), true);
        List<ApiMdlModelDir> childrens = apiMdlModelDirs.get(0).getChildren();
        for (int i = 0; i < childrens.size(); i++) {
            ApiMdlModelDir chi = childrens.get(i);
            String result = chi.getMdlModelResult().getResult();
            JSONObject resultJson = getModelResultFromDivisionData(result, divisionCode);
            JSONObject dataJson = resultJson.getJSONObject(ModelConst.MODEL_STATISTICAL_STATISTICINFORMATION).getJSONObject(ModelConst.MODEL_VALUE_TYPE_CURRENT);
            if("土地资源".equals(chi.getAlias())) {
                strHtml.append("<h"+(2)+" style=\"font-family:'宋体';font-size:18px;\">" + (i + 1) + "、" + chi.getAlias() + "</h"+(2)+">");
                strHtml.append("<p style=\"font-family:'宋体';font-size:18px;text-indent:2em;\">");
                StringBuffer phtml = new StringBuffer();
                JSONObject z = dataJson.getJSONObject("压力中等");
                if(z != null) {
                    phtml.append("压力中等的面积为").append(df.format(z.getDouble("Area_Value")/100000000.0)).append("万公顷。");
                }
                JSONObject d = dataJson.getJSONObject("压力大");
                if(d != null) {
                    phtml.append("压力大的面积为").append(df.format(d.getDouble("Area_Value")/100000000.0)).append("万公顷。");
                }
                if(phtml.length() > 0) {
                    phtml.insert(0, divisionText + chi.getAlias() + "超载分析中");
                    phtml.append("历年建设用地年均增速的发展趋势如下图所示：");
                }
                strHtml.append(phtml).append("</p>");
                JSONArray jsonArray = iIdtIndicatorsDirService.getIndexFactorGrowthRate(chi.getAlias(), divisionCode);
                for (int j = 0; j < jsonArray.size(); j++) {
                    Map<String,String> echartOptions = (Map<String,String>) dataMap.get("echartOptions");
                    if (echartOptions == null){
                        echartOptions = new HashMap<>();
                        dataMap.put("echartOptions",echartOptions);
                    }
                    String uuid = UuidUtil.get32UUID();
                    echartOptions.put(uuid + j, "option = " + jsonArray.get(j).toString());
                    strHtml.append("<img data-id=\"").append(uuid + j).append("\">");
                    strHtml.append("<p style=\"font-family:'宋体';font-size:16px;text-indent:2em;text-align:center\">");
                    strHtml.append(jsonArray.getJSONObject(j).getString("name"));
                    strHtml.append("</p>");
                }
            }
            if("水资源".equals(chi.getAlias())) {
                strHtml.append("<h"+(2)+" style=\"font-family:'宋体';font-size:18px;\">" + (i + 1) + "、" + chi.getAlias() + "</h"+(2)+">");
                strHtml.append("<p style=\"font-family:'宋体';font-size:18px;text-indent:2em;\">");
                StringBuffer phtml = new StringBuffer();
                JSONObject z = dataJson.getJSONObject("临界超载");
                if(z != null) {
                    phtml.append("临界超载的面积为").append(df.format(z.getDouble("Area_Value")/100000000.0)).append("万公顷。");
                }
                JSONObject d = dataJson.getJSONObject("超载");
                if(d != null) {
                    phtml.append("超载的面积为").append(df.format(d.getDouble("Area_Value")/100000000.0)).append("万公顷。");
                }
                if(phtml.length() > 0) {
                    phtml.insert(0, divisionText + chi.getAlias() + "超载分析中");
                    phtml.append("。历年用水总量年均增速、地下水供应量年均增速的发展趋势如下图所示：");
                }
                strHtml.append(phtml).append("</p>");
                JSONArray jsonArray = iIdtIndicatorsDirService.getIndexFactorGrowthRate(chi.getAlias(), divisionCode);
                for (int j = 0; j < jsonArray.size(); j++) {
                    Map<String,String> echartOptions = (Map<String,String>) dataMap.get("echartOptions");
                    if (echartOptions == null){
                        echartOptions = new HashMap<>();
                        dataMap.put("echartOptions",echartOptions);
                    }
                    String uuid = UuidUtil.get32UUID();
                    echartOptions.put(uuid + j, "option = " + jsonArray.get(j).toString());
                    strHtml.append("<img data-id=\"").append(uuid + j).append("\">");
                    strHtml.append("<p style=\"font-family:'宋体';font-size:16px;text-indent:2em;text-align:center\">");
                    strHtml.append(jsonArray.getJSONObject(j).getString("name"));
                    strHtml.append("</p>");
                }
            }
            if("环境".equals(chi.getAlias())) {
                strHtml.append("<h"+(2)+" style=\"font-family:'宋体';font-size:18px;\">" + (i + 1) + "、" + chi.getAlias() + "</h"+(2)+">");
                strHtml.append("<p style=\"font-family:'宋体';font-size:18px;text-indent:2em;\">");
                StringBuffer phtml = new StringBuffer();
                JSONObject z = dataJson.getJSONObject("接近超标");
                if(z != null) {
                    phtml.append("接近超标的面积为").append(df.format(z.getDouble("Area_Value")/100000000.0)).append("万公顷。");
                }
                JSONObject d = dataJson.getJSONObject("超标");
                if(d != null) {
                    phtml.append("超标的面积为").append(df.format(d.getDouble("Area_Value")/100000000.0)).append("万公顷。");
                }
                if(phtml.length() > 0) {
                    phtml.insert(0, divisionText + chi.getAlias() + "超载分析中");
                    phtml.append("大气污染指标中二氧化硫年均增速、PM2.5年均增速；水污染指标中废水中氨氮含量年均增速、化学需氧量年均增速的发展趋势如下图所示：");
                }
                strHtml.append(phtml).append("</p>");
                JSONArray jsonArray = iIdtIndicatorsDirService.getIndexFactorGrowthRate(chi.getAlias(), divisionCode);
                for (int j = 0; j < jsonArray.size(); j++) {
                    Map<String,String> echartOptions = (Map<String,String>) dataMap.get("echartOptions");
                    if (echartOptions == null){
                        echartOptions = new HashMap<>();
                        dataMap.put("echartOptions",echartOptions);
                    }
                    String uuid = UuidUtil.get32UUID();
                    echartOptions.put(uuid + j, "option = " + jsonArray.get(j).toString());
                    strHtml.append("<img data-id=\"").append(uuid + j).append("\">");
                    strHtml.append("<p style=\"font-family:'宋体';font-size:16px;text-indent:2em;text-align:center\">");
                    strHtml.append(jsonArray.getJSONObject(j).getString("name"));
                    strHtml.append("</p>");
                }
            }
            if("生态".equals(chi.getAlias())) {
                strHtml.append("<h"+(2)+" style=\"font-family:'宋体';font-size:18px;\">" + (i + 1) + "、" + chi.getAlias() + "</h"+(2)+">");
                strHtml.append("<p style=\"font-family:'宋体';font-size:18px;text-indent:2em;\">");
                StringBuffer phtml = new StringBuffer();
                JSONObject z = dataJson.getJSONObject("健康度中等");
                if(z != null) {
                    phtml.append("健康度中等的面积为").append(df.format(z.getDouble("Area_Value")/100000000.0)).append("万公顷。");
                }
                JSONObject d = dataJson.getJSONObject("健康度低");
                if(d != null) {
                    phtml.append("健康度低的面积为").append(df.format(d.getDouble("Area_Value")/100000000.0)).append("万公顷。");
                }
                if(phtml.length() > 0) {
                    phtml.insert(0, divisionText + chi.getAlias() + "超载分析中");
                    phtml.append("历年水土流失年均增速的发展趋势如下图所示：");

                }
                strHtml.append(phtml).append("</p>");
                JSONArray jsonArray = iIdtIndicatorsDirService.getIndexFactorGrowthRate(chi.getAlias(), divisionCode);
                for (int j = 0; j < jsonArray.size(); j++) {
                    Map<String,String> echartOptions = (Map<String,String>) dataMap.get("echartOptions");
                    if (echartOptions == null){
                        echartOptions = new HashMap<>();
                        dataMap.put("echartOptions",echartOptions);
                    }
                    String uuid = UuidUtil.get32UUID();
                    echartOptions.put(uuid + j, "option = " + jsonArray.get(j).toString());
                    strHtml.append("<img data-id=\"").append(uuid + j).append("\">");
                    strHtml.append("<p style=\"font-family:'宋体';font-size:16px;text-indent:2em;text-align:center\">");
                    strHtml.append(jsonArray.getJSONObject(j).getString("name"));
                    strHtml.append("</p>");
                }
            }
            if("农业".equals(chi.getAlias())) {
                strHtml.append("<h"+(2)+" style=\"font-family:'宋体';font-size:18px;\">" + (i + 1) + "、" + chi.getAlias() + "</h"+(2)+">");
                strHtml.append("<p style=\"font-family:'宋体';font-size:18px;text-indent:2em;\">");
                StringBuffer phtml = new StringBuffer();
                JSONObject z = dataJson.getJSONObject("相对稳定");
                if(z != null) {
                    phtml.append("相对稳定的面积为").append(df.format(z.getDouble("Area_Value")/100000000.0)).append("万公顷。");
                }
                JSONObject d = dataJson.getJSONObject("恶化");
                if(d != null) {
                    phtml.append("恶化的面积为").append(df.format(d.getDouble("Area_Value")/100000000.0)).append("万公顷。");
                }
                if(phtml.length() > 0) {
                    phtml.insert(0, divisionText + chi.getAlias() + "超载分析中");
                    phtml.append("历年土壤有机质含量年均增速的发展趋势如下图所示：");
                }
                strHtml.append(phtml).append("</p>");
                JSONArray jsonArray = iIdtIndicatorsDirService.getIndexFactorGrowthRate(chi.getAlias(), divisionCode);
                for (int j = 0; j < jsonArray.size(); j++) {
                    Map<String,String> echartOptions = (Map<String,String>) dataMap.get("echartOptions");
                    if (echartOptions == null){
                        echartOptions = new HashMap<>();
                        dataMap.put("echartOptions",echartOptions);
                    }
                    String uuid = UuidUtil.get32UUID();
                    echartOptions.put(uuid + j, "option = " + jsonArray.get(j).toString());
                    strHtml.append("<img data-id=\"").append(uuid + j).append("\">");
                    strHtml.append("<p style=\"font-family:'宋体';font-size:16px;text-indent:2em;text-align:center\">");
                    strHtml.append(jsonArray.getJSONObject(j).getString("name"));
                    strHtml.append("</p>");
                }
            }
            if("城市".equals(chi.getAlias())) {
                strHtml.append("<h"+(2)+" style=\"font-family:'宋体';font-size:18px;\">" + (i + 1) + "、" + chi.getAlias() + "</h"+(2)+">");
                strHtml.append("<p style=\"font-family:'宋体';font-size:18px;text-indent:2em;\">");
                StringBuffer phtml = new StringBuffer();
                JSONObject z = dataJson.getJSONObject("临界超载");
                if(z != null) {
                    phtml.append("临界超载的面积为").append(df.format(z.getDouble("Area_Value")/100000000.0)).append("万公顷。");
                }
                JSONObject d = dataJson.getJSONObject("超载");
                if(d != null) {
                    phtml.append("超载的面积为").append(df.format(d.getDouble("Area_Value")/100000000.0)).append("万公顷。");
                }
                if(phtml.length() > 0) {
                    phtml.insert(0, divisionText + chi.getAlias() + "超载分析中");
                    phtml.append("历年河流黑臭水体溶解氧年均增速的发展趋势如下图所示：");
                }
                strHtml.append(phtml).append("</p>");
                JSONArray jsonArray = iIdtIndicatorsDirService.getIndexFactorGrowthRate(chi.getAlias(), divisionCode);
                for (int j = 0; j < jsonArray.size(); j++) {
                    Map<String,String> echartOptions = (Map<String,String>) dataMap.get("echartOptions");
                    if (echartOptions == null){
                        echartOptions = new HashMap<>();
                        dataMap.put("echartOptions",echartOptions);
                    }
                    String uuid = UuidUtil.get32UUID();
                    echartOptions.put(uuid + j, "option = " + jsonArray.get(j).toString());
                    strHtml.append("<img data-id=\"").append(uuid + j).append("\">");
                    strHtml.append("<p style=\"font-family:'宋体';font-size:16px;text-indent:2em;text-align:center\">");
                    strHtml.append(jsonArray.getJSONObject(j).getString("name"));
                    strHtml.append("</p>");
                }
            }
        }

        this.replaceEchartImgForHtml((Map<String,String>)dataMap.getOrDefault("echartOptions", new HashMap<>()), strHtml);
        String wordName = this.createWord("【决策支持】资源环境承载能力决策分析报告.docx", fieldMap, null, null, null, strHtml.toString());
        return wordName;
    }

    /**
     * @描述: 导出【潜力评估报告.docx】
     * @入参: modelTypeCode 模型体系编码，不能为空
     * @入参: divisionCode 行政区划编码，不能为空
     * @入参: year 年份，不能为空
     * @出参: 报告临时文件地址
     * @作者: 陈宏成
     * @日期: 2022-04-14
     **/
    @Override
    public String exportPotentialAssessmentWord(String modelTypeCode, String divisionCode, Integer year) throws Exception{
        MapDivision division = iMapClient.mateByCode(divisionCode);
        String divisionText = division == null ? "" : division.getName();
        // 查询模型
        List<ApiMdlModelDir> mdlModelDirs = this.listModelDirs(modelTypeCode, null, String.valueOf(year), true);
        // 生成word临时文件
        StringBuilder stringBuilder = new StringBuilder("");
        // 遍历
        Map<String,Object> dataMap = new HashMap<>();
        dataMap.put("divisionCode",divisionCode);
        dataMap.put("divisionText",divisionText);
        String divisionCodeNoZero = CommonUtil.divisionTrimZero(divisionCode);
        if (divisionCodeNoZero.length() <= 2) {
            dataMap.put("divisionLevel","省");
        } else if (divisionCodeNoZero.length() <= 4) {
            dataMap.put("divisionLevel","市");
        } else if (divisionCodeNoZero.length() <= 6) {
            dataMap.put("divisionLevel","区/镇");
        } else {
            dataMap.put("divisionLevel","县");
        }
        dataMap.put("year",year);
        for(ApiMdlModelDir mdlModelDir : mdlModelDirs.get(0).getChildren()) {
            Object tableNum = dataMap.getOrDefault("tableNum", 0);
            dataMap.put("tableNum",((Integer)tableNum) + 1);
            String htmlStr = this.buildHtmlStrForPotentialAssessmentWord(mdlModelDir, dataMap);
            stringBuilder.append(htmlStr);
        }
        // 生成word文档
        Map<String, Object> fieldMap = new HashMap<>(2);
        fieldMap.put("XZQ",divisionText);
        fieldMap.put("NF",year);
        stringBuilder.insert(0,"<style>table,td,th{font-size:12px;border:1px solid grey;padding:5px;width:555px;text-align:center;}p,span,h1,h2,h3,div{font-family:'宋体';}*{font-family:'宋体';}</style>");
        String wordName = this.createWord("【潜力评估】报告模板.docx", fieldMap, null, null, null, stringBuilder.toString());
        return wordName;
    }

    @Override
    public String exportSpecialRegulationsReviewWord(String jsonData, String name, String divisionCode, String deptId) throws Exception {
        //解析json数据
        JSONArray jsonArray = JSON.parseArray(jsonData);
        Map<String, Object> fieldMap = new HashMap<>();
        fieldMap.put("NAME", name);
        fieldMap.put("TIME", DateUtil.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss"));
        fieldMap.put("DEPT", deptId);
        //生成临时word文件
        StringBuilder strHtml = new StringBuilder("");
        List<JSONObject> unLike = new ArrayList<>();
        List<JSONObject> like = new ArrayList<>();
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject object = jsonArray.getJSONObject(i);
            if("0".equals(object.getString("isPass"))){
                unLike.add(object);
            } else {
                like.add(object);
            }
        }
        strHtml.append("<h"+(1)+" style=\"font-family:'宋体';font-size:18px;\">一、审查结论</h"+(1)+">");
        strHtml.append("<p style=\"text-indent:2em;\">" + name + "与");
        for (int i = 0; i < unLike.size(); i++) {
            JSONObject object = unLike.get(i);
            strHtml.append(object.getString("name"));
            if(!(i == unLike.size() - 1)) {
                strHtml.append("、");
            }
        }
        strHtml.append("冲突");
        if(!CollectionUtils.isEmpty(like)) {
            strHtml.append("与");
            for (int i = 0; i < like.size(); i++) {
                JSONObject object = like.get(i);
                strHtml.append(object.getString("name"));
                if(!(i == like.size() - 1)) {
                    strHtml.append("、");
                }
            }
            strHtml.append("一致，");
        }
        strHtml.append("审查详情如下:</p>");
        StringBuilder tableStringBuilder = new StringBuilder();
        tableStringBuilder.append("<table style =\"border-collapse:collapse;border: solid 1px #000;font-family:'宋体';\">")
                .append("<tr>")
                .append("<td>序号</td>")
                .append("<td>审查对象</td>")
                .append("<td>是否冲突</td>")
                .append("<td>冲突面积（公顷）</td>")
                .append("</tr>");
        int num = 1;
        for (int i = 0; i < unLike.size(); i++) {
            JSONObject gridData = unLike.get(i).getJSONArray("gridData").getJSONObject(0);
            tableStringBuilder.append("<tr>")
                    .append("<td>").append(num++).append("</td>")
                    .append("<td>").append(unLike.get(i).getString("name")).append("</td>")
                    .append("<td><font color='red'>").append("冲突").append("</font></td>")
                    .append("<td>").append(convertUnit(unLike.get(i).getString("unit"), gridData.getString("area"))).append("</td>")
                    .append("</tr>");
        }
        for (int i = 0; i < like.size(); i++) {
            tableStringBuilder.append("<tr>")
                    .append("<td>").append(num++).append("</td>")
                    .append("<td>").append(like.get(i).getString("name")).append("</td>")
                    .append("<td><font color='green'>").append("一致").append("</font></td>")
                    .append("<td>-</td>")
                    .append("</tr>");
        }
        tableStringBuilder.append("</table>");
        strHtml.append(tableStringBuilder);
        strHtml.append("<h"+(1)+" style=\"font-family:'宋体';font-size:18px;\">二、审查明细</h"+(1)+">");
        //处理冲突数据的表格
        StringBuilder tableHtml = new StringBuilder();
        for (JSONObject object : unLike) {
            tableHtml.append("<p style=\"text-align:center;\">").append(name).append("与").append(object.getString("name")).append("矛盾冲突</p>")
                    .append("<table style =\"border-collapse:collapse;border: solid 1px #000;font-family:'宋体';\">")
                    .append("<tr>")
                    .append("<td colspan=\"2\">行政区划名称</td>")
                    .append("<td>冲突面积（公顷）</td>")
                    .append("<td>面积占比（%）</td>")
                    .append("</tr>");
            JSONObject gridData = object.getJSONArray("gridData").getJSONObject(0);
            JSONArray children = gridData.getJSONArray("children");
            for (int j = 0; j < children.size(); j++) {
                JSONObject child = children.getJSONObject(j);
                tableHtml.append("<tr>")
                        .append("<td colspan=\"2\">").append(iMapClient.getNameByCode(child.getString("xzqdm"))).append("</td>")
//                        .append("<td colspan=\"2\">").append(child.getString("xzqdm")).append("</td>")
                        .append("<td>").append(convertUnit(object.getString("unit"), child.getString("area"))).append("</td>")
                        .append("<td>").append(new BigDecimal(child.getString("ratio")).setScale(4, BigDecimal.ROUND_HALF_UP)).append("</td>")
                        .append("</tr>");
            }
            tableHtml.append("<tr>")
                    .append("<td rowspan=\"2\">合计</td>")
                    .append("<td>冲突面积</td>")
                    .append("<td>").append(convertUnit(object.getString("unit"), gridData.getString("area"))).append("</td>")
                    .append("<td>").append(gridData.getString("ratio")).append("</td>");
            tableHtml.append("<tr>")
                    .append("<td>不冲突面积</td>")
                    .append("<td>").append(convertUnit(object.getString("unit"), gridData.getString("unArea"))).append("</td>")
                    .append("<td>").append(BigDecimal.valueOf(1 - Double.parseDouble(gridData.getString("ratio"))).setScale(4, BigDecimal.ROUND_HALF_UP)).append("</td>")
                    .append("</tr></table>");
        }
        strHtml.append(tableHtml);
        strHtml.insert(0,"<style>table,td,th{font-size:12px;border:1px solid grey;padding:5px;width:555px;text-align:center;}p,span,h1,h2,h3,div{font-family:'宋体';}*{font-family:'宋体';}</style>");
        return createWord("【专规审查】报告模板.docx", fieldMap, null, null, null, strHtml.toString());
    }

    /**
     * @作者: 面积单位转换
     * @日期: 2022/07/14
     * @描述: 专项规划审查导出报告
     */
    private String convertUnit(String unit, String area){
        String unitName;
        BigDecimal bigDecimal = new BigDecimal(area);
        if("1".equals(unit)) {
            return bigDecimal.setScale(4, BigDecimal.ROUND_HALF_UP).toString();
        } else if("10000".equals(unit)) {
            unitName = "平方米";
        } else {
            unitName = "平方千米";
        }
        String convert = UnitConvertUnit.areaConver(area, unitName, "公顷");
        return new BigDecimal(convert).setScale(4, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 为【专题评估报告.docx】构建html内容
     * @入参: modelDir 模型目录，需要是树状结构，不能为空
     * @入参: dataMap 用到的一些上下文数据，例如divisionCode、year、tableNum、divisionText
     * @出参: 一个模型的html输出内容
     * @throws IOException
     * @作者: 陈宏成
     * @日期: 2022/04/15
     */
    private String buildHtmlStrForPotentialAssessmentWord(ApiMdlModelDir modelDir, Map<String,Object> dataMap) throws IOException {
        if (CollectionUtils.isEmpty(modelDir.getChildren())){
            return "";
        }
        StringBuilder stringBuilder = new StringBuilder("");
        Integer tableNum = (Integer)dataMap.getOrDefault("tableNum", 1);
        String titleIndexStr = this.getTitleIndexStr(1, tableNum);
        String divisionCode = (String)dataMap.get("divisionCode");
        String divisionLevel = (String)dataMap.get("divisionLevel");
        // 标题
        stringBuilder.append("<h2 style=\"font-family:'宋体';font-size:18px;\">" + titleIndexStr + modelDir.getName()+"</h2>");
        // 正文上部，固定内容
        if (modelDir.getName().contains("农业")){
            stringBuilder.append("<p style=\"font-family:'宋体';font-size:18px;text-indent:2em;\">")
                    .append("在双评价结果中的农业生产适宜区的基础上，在农业生产适宜区基础上，依次扣除生态保护极重要区、现状城镇（不含农村居民点）及基础设施建设用地、连片分布的林地与优质草地、生态保护红线内面积等，识别农业生产适宜区剩余可用空间。")
                    .append("</p>");
        }else if (modelDir.getName().contains("建设")){
            stringBuilder.append("<p style=\"font-family:'宋体';font-size:18px;text-indent:2em;\">")
                    .append("在城镇建设适宜区基础上，依次扣除生态保护极重要区、现状城镇（不含农村居民点）及基础设施建设用地、连片分布的现状优质耕地、生态保护红线内面积等，识别城镇建设适宜区剩余可用空间。")
                    .append("</p>");
        }

        // 正文下部，非固定内容
        stringBuilder.append("<p style=\"font-family:'宋体';font-size:18px;text-indent:2em;\">").append("全").append(divisionLevel);
        // 获取分析范围
        List<ApiMdlModelDir> subModelsList = modelDir.getChildren().stream().filter(model -> {
            // 返回名字包含“内”的目录，这些都是分析的子模型列表
            return model.getType() == 1 && model.getName().contains("内") && !CollectionUtils.isEmpty(model.getChildren());
        }).collect(Collectors.toList());
        String scope = "";
        if (!CollectionUtils.isEmpty(subModelsList)){
            String name = subModelsList.get(0).getName();
            scope = name.substring(0, name.indexOf("内"));
            // 是否添加现状面积文本
            boolean isPresent = true;
            // 遍历子模型
            for(ApiMdlModelDir apiMdlModelDir : subModelsList) {
                // 解析json结果
                if (Objects.isNull(apiMdlModelDir.getChildren().get(0).getMdlModelResult())){
                    continue;
                }
                List<Map<String, Object>> oneDivisionDataFromModelResult = this.getOneDivisionDataFromModelResult(apiMdlModelDir.getChildren().get(0).getMdlModelResult().getResult(),divisionCode, false );
                if (CollectionUtils.isEmpty(oneDivisionDataFromModelResult)){
                    continue;
                }
                if (isPresent){
                    // 现状面积
                    stringBuilder.append(scope)
                            .append("面积为")
                            .append(this.blankReturn((String) oneDivisionDataFromModelResult.get(0).get("OtherArea_Value"),"--"))
                            .append(this.blankReturn((String)oneDivisionDataFromModelResult.get(0).get("OtherArea_Unit"),"--"))
                            .append("。").append(scope).append("内的");
                    isPresent = false;
                }
                String analysisObject = apiMdlModelDir.getName().substring(apiMdlModelDir.getName().indexOf("内") + 1);
                // 冲突面积
                stringBuilder.append(analysisObject).append("面积为")
                        .append(this.blankReturn((String) oneDivisionDataFromModelResult.get(0).get("Area_Value"),"--"))
                        .append(this.blankReturn((String) oneDivisionDataFromModelResult.get(0).get("Area_Unit"),"--"))
                        .append("，");
            }
        }
        // 表格
        StringBuilder tableStringBuilder = new StringBuilder();
        // 剩余可用面积
        Optional<ApiMdlModelDir> potentialOpt = modelDir.getChildren().stream().filter(model -> {
            // 返回名字包含“潜力分析”的目录，这个就是剩余可用面积的内容
            return model.getType() == 1 && model.getName().contains("潜力分析") && !CollectionUtils.isEmpty(model.getChildren());
        }).findFirst();
        if (potentialOpt.isPresent()){
            // 没有模型结果，直接跳过
            if (Objects.nonNull(potentialOpt.get().getChildren().get(0).getMdlModelResult())){
                List<Map<String, Object>> oneDivisionDataFromModelResult = this.getOneDivisionDataFromModelResult(potentialOpt.get().getChildren().get(0).getMdlModelResult().getResult(),divisionCode, true );
                if (!CollectionUtils.isEmpty(oneDivisionDataFromModelResult)){
                    Optional<Map<String, Object>> currentDivisionResult = oneDivisionDataFromModelResult.stream().filter(map -> Objects.equals(divisionCode, map.get("divisionCode"))).findFirst();
                    List<Map<String, Object>> subDivisionResult = oneDivisionDataFromModelResult.stream().filter(map -> !Objects.equals(divisionCode, map.get("divisionCode"))).sorted(new Comparator<Map<String, Object>>() {
                        @Override
                        public int compare(Map<String, Object> o1, Map<String, Object> o2) {
                            String area_value1 = (String) o1.get("Area_Value");
                            Double area_valued1 = Double.valueOf(StringUtils.hasText(area_value1)? area_value1: "0");

                            String area_value2 = (String) o2.get("Area_Value");
                            Double area_valued2 = Double.valueOf(StringUtils.hasText(area_value2)? area_value2: "0");

                            return area_valued2.compareTo(area_valued1);
                        }
                    }).collect(Collectors.toList());

                    tableStringBuilder.append("<p style=\"text-align:center;\">表").append(tableNum).append("：").append(modelDir.getName()).append("</p>")
                            .append("<table style =\"border-collapse:collapse;border: solid 1px #000;font-family:'宋体';\">")
                            .append("<tr>")
                            .append("<td>序号</td>")
                            .append("<td>行政区</td>")
                            .append("<td>潜力面积（").append(this.blankReturn((String) oneDivisionDataFromModelResult.get(0).get("Area_Unit"), "--")).append("）</td>")
                            .append("</tr>");

                    if (currentDivisionResult.isPresent()){
                        stringBuilder.append(scope).append("剩余可用面积为")
                                .append(this.blankReturn((String) currentDivisionResult.get().get("Area_Value"),"--"))
                                .append(this.blankReturn((String) currentDivisionResult.get().get("Area_Unit"),"--"));
                        tableStringBuilder.append("<tr>")
                                .append("<td>1</td>")
                                .append("<td>").append(this.blankReturn((String) currentDivisionResult.get().get("divisionText"),"--")).append("</td>")
                                .append("<td>").append(this.blankReturn((String) currentDivisionResult.get().get("Area_Value"),"--")).append("</td>")
                                .append("</tr>");
                    }
                    if (!CollectionUtils.isEmpty(subDivisionResult)){
                        stringBuilder.append("，其中").append(this.blankReturn((String) subDivisionResult.get(0).get("divisionText"), "--")).append("境内剩余可用面积最多，为")
                                .append(this.blankReturn((String) subDivisionResult.get(0).get("Area_Value"), "--"))
                                .append(this.blankReturn((String) subDivisionResult.get(0).get("Area_Unit"), "--")).append("。");
                        for(int i = 0; i < subDivisionResult.size(); i++) {
                            tableStringBuilder.append("<tr>")
                                    .append("<td>").append( i + 2 ).append("</td>")
                                    .append("<td>").append(this.blankReturn((String) subDivisionResult.get(i).get("divisionText"),"--")).append("</td>")
                                    .append("<td>").append(this.blankReturn((String) subDivisionResult.get(i).get("Area_Value"),"--")).append("</td>")
                                    .append("</tr>");
                        }
                    }
                    // 表格首尾
                    tableStringBuilder.append("</tr></table>");
                }
            }
        }

        stringBuilder.append("</p>");
        stringBuilder.append(tableStringBuilder);
        return stringBuilder.toString();
    }

    private String blankReturn(String value, String blankReturn){
        return StringUtils.hasText(value)? value: blankReturn;
    }

    private JSONObject getModelResultFromDivisionData(String result, String divisionCode) {
        JSONObject object = JSONObject.parseObject(result);
        JSONObject rootGroupItem = object.getJSONObject(ModelConst.MODEL_LEVEL_ROOTGROUPITEM);
        if(divisionCode.equals(rootGroupItem.getString(ModelConst.MODEL_FEATURE_DIVISION_GROUPITEMCODE))) {
            return rootGroupItem;
        } else {
            return getModelResultFromDivisionData(rootGroupItem.getJSONArray(ModelConst.MODEL_LEVEL_SUBLEVEL1GROUPITEM), divisionCode);
        }
    }

    private JSONObject getModelResultFromDivisionData(JSONArray results, String divisionCode) {
       for (int i = 0; i < results.size(); i++) {
           JSONObject object = results.getJSONObject(i);
           if (divisionCode.equals(object.getString(ModelConst.MODEL_FEATURE_DIVISION_GROUPITEMCODE))) {
               return object;
            } else {
               return getModelResultFromDivisionData(object.getJSONArray(ModelConst.MODEL_LEVEL_SUBLEVEL1GROUPITEM), divisionCode);
            }
        }
       return null;
    }

    /**
     * 为【专题评估报告.docx】构建html内容
     * @入参: modelDir 模型目录，需要是树状结构，不能为空
     * @入参: dataMap 用到的一些上下文数据，例如divisionCode、year、tableNum、levelNum_X
     * @出参: 一个模型的html输出内容
     * @throws IOException
     * @作者: 陈宏成
     * @日期: 2021/02/04
     */
    private String buildHtmlStrForThematicAssessmentWord(ApiMdlModelDir modelDir, Map<String,Object> dataMap) throws IOException {
        StringBuilder stringBuilder = new StringBuilder("");
        int level = (Integer) dataMap.get("level");
        String divisionCode = (String) dataMap.get("divisionCode");
        List<String> modelDirNameList = (List<String>)dataMap.get("modelDirNameList");
        if (modelDir.getType() == 1){
            // 如果是目录，递归其子级，如果子级有构建内容，就输出，否则不输出
            if(modelDir.getChildren() != null && !modelDir.getChildren().isEmpty()){
                dataMap.put("levelNum_" + (level+1),0);
                for(ApiMdlModelDir child : modelDir.getChildren()) {
                    dataMap.put("level",level+1);
                    modelDirNameList.add(modelDir.getName());
                    dataMap.put("modelDirNameList",modelDirNameList);
                    // 递归处理子节点
                    String htmlStr = this.buildHtmlStrForThematicAssessmentWord(child,dataMap);
                    modelDirNameList.remove(modelDirNameList.size() - 1);
                    dataMap.put("modelDirNameList",modelDirNameList);
                    dataMap.put("level",level);
                    if (StringUtils.hasText(htmlStr)){
                        // 如果子级构建了内容，那么本级也要构建标题
                        stringBuilder.append(htmlStr);
                    }
                }
                dataMap.remove("levelNum_" + (level+1));
                if (stringBuilder.length() > 0){
                    int titleIndex = (Integer) dataMap.get("levelNum_"+level) + 1;
                    dataMap.put("levelNum_"+level, titleIndex);
                    String titleIndexStr = this.getTitleIndexStr(level,titleIndex);
                    // 本级的标题
                    stringBuilder.insert(0,"<h"+(level+1)+" style=\"font-family:'宋体';font-size:18px;\">" + titleIndexStr + modelDir.getName()+"</h"+(level+1)+">");
                }
            }
        }else {
            // 如果是模型，要构建自身输出的html内容
            // 解析json
            if (modelDir.getMdlModelResult() == null || !StringUtils.hasText(modelDir.getMdlModelResult().getResult())){
                return "";
            }
            // 解析json数据
            List<Map<String, Object>> listDataFromJson = this.getOneDivisionDataFromModelResult(modelDir.getMdlModelResult().getResult(),divisionCode,false);
            if (listDataFromJson.isEmpty()) {
                // 如果没有这个行政区的数据，直接返回空
                return "";
            }
            // 对该行政区的数据进行排序
            Map<String, Object> ModelResultData = listDataFromJson.get(0);
            List<Map<String, String>> items = (List<Map<String, String>>)ModelResultData.get("items");
            items = items.stream().sorted((item1,item2)->{
                double value1 = Double.parseDouble(item1.getOrDefault("value", "0.0"));
                double value2 = Double.parseDouble(item2.getOrDefault("value", "0.0"));
                return Math.abs(value1 - value2) < 0.00001? 0: value1 > value2? -1:  1;
            }).collect(Collectors.toList());
            // 最大占比,最小占比
            double maxProportion,minProportion;
            double totalValue = Double.parseDouble((String) (ModelResultData.get("total_value")));
            if (Math.abs(totalValue - 0) < 0.00001){
                // 如果总数为0
                maxProportion = 0;
                minProportion = 0;
            }else{
                maxProportion = Double.parseDouble(items.get(0).get("value")) / Double.parseDouble((String)(ModelResultData.get("total_value"))) * 100.0;
                minProportion = Double.parseDouble(items.get(items.size() - 1).get("value")) / Double.parseDouble((String)(ModelResultData.get("total_value"))) * 100.0;
            }
            // 拼接html内容
            // 获取模型实际内容，例如【生态保护红线_生态红线内三调数据_监测值】，只要【生态红线内三调数据】
            String modelName = modelDir.getMdlModel().getName();
            modelName = modelName.substring(modelName.indexOf("_") + 1);
            modelName = modelName.substring(0,modelName.lastIndexOf("_"));
            int titleIndex = (Integer) dataMap.get("levelNum_"+level) + 1;
            dataMap.put("levelNum_"+level, titleIndex);
            stringBuilder.append("<h"+(level+1)+" style=\"font-family:'宋体';font-size:18px;\">("+titleIndex+")" + modelDir.getMdlModel().getName()+"</h"+(level+1)+">")
                    .append("<p style=\"font-family:'宋体';font-size:18px;text-indent:2em;\">")
                    .append(modelName).append("内").append(items.get(0).get("key")).append("面积最多为")
                    .append(this.holdTwoDecimal(items.get(0).get("value")))
                    .append(items.get(0).get("unit"))
                    .append("，占比").append(this.holdTwoDecimal(String.valueOf(maxProportion))).append("%").append("；")
                    .append(items.get(items.size() - 1 ).get("key")).append("面积最少为").append(this.holdTwoDecimal(items.get(items.size() - 1 ).get("value")))
                    .append(items.get(items.size() - 1 ).get("unit"))
                    .append("，占比").append(this.holdTwoDecimal(String.valueOf(minProportion))).append("%").append("。").append("</p>");
            // 构建echart图表
            // 获取使用的图表配置文件
            String echartsType = this.getEchartsType(dataMap);
            // 获取option配置
            String option = (String) dataMap.get( echartsType );
            if (!StringUtils.hasText(option)){
                ClassPathResource resource = new ClassPathResource("template/" + echartsType);
                InputStream inputStream = resource.getInputStream();
                option = FileUtil.txt2String(inputStream, "utf-8");
                dataMap.put(echartsType , option);
            }
            List<Map<String, String>> chartNameValueDataList = items.stream().map(item -> {
                Map<String, String> map = new HashMap<>();
                map.put("name", item.get("key"));
                map.put("value", this.holdTwoDecimal(item.get("value")));
                return map;
            }).collect(Collectors.toList());
            List<String> chartNameDataList = items.stream().map(item -> {
                return item.get("key");
            }).collect(Collectors.toList());
            List<String> chartValueDataList = items.stream().map(item -> {
                return this.holdTwoDecimal(item.get("value"));
            }).collect(Collectors.toList());
            option = option.replace("${titleName}",modelDir.getMdlModel().getName());
            option = option.replace("${nameValueArray}",JSON.toJSONString(chartNameValueDataList));
            option = option.replace("${nameArray}",JSON.toJSONString(chartNameDataList));
            option = option.replace("${valueArray}",JSON.toJSONString(chartValueDataList));
            // 将图表结果暂存
            Map<String,String> echartOptions = (Map<String,String>)dataMap.get("echartOptions");
            if (echartOptions == null){
                echartOptions = new HashMap<>();
                dataMap.put("echartOptions",echartOptions);
            }
            echartOptions.put(modelDir.getModelId(), option);
            // 在html中预留埋点，方便后面直接替换
            stringBuilder.append("<img data-id=\"").append(modelDir.getModelId()).append("\">");
        }
        return stringBuilder.toString();
    }


    /**
     * 仅用于导出【专题评估报告.docx】，根据数据集中的父目录列表，判断使用什么类型的图表
     * @入参: dataMap 数据集
     * @出参: echarts配置文件名
     * @作者: 陈宏成
     * @日期: 2021/02/04
     */
    private String getEchartsType(Map<String,Object> dataMap){
        List<String> modelDirNameList = (List<String>)dataMap.get("modelDirNameList");
        if(modelDirNameList == null || modelDirNameList.isEmpty()){
            return "pie_chart_option.ftl";
        }
        for(String name : modelDirNameList) {
            if (name.contains("协调评估")){
                return "bar_chart_option.ftl";
            }
            if (name.contains("现状评估")){
                for(String s : modelDirNameList) {
                    if (s.contains("永久基本农田")){
                        Integer num = (Integer)dataMap.getOrDefault("永久基本农田-现状评估", 0) + 1;
                        dataMap.put("永久基本农田-现状评估", num);
                        return num <= 2? "bar_chart_option.ftl": "pie_chart_option.ftl";
                    }
                    if (s.contains("城镇开发边界")){
                        Integer num = (Integer)dataMap.getOrDefault("城镇开发边界-现状评估", 0) + 1;
                        dataMap.put("城镇开发边界-现状评估", num);
                        return num <= 2? "pie_chart_option.ftl": "bar_chart_option.ftl";
                    }
                }
                return "pie_chart_option.ftl";
            }
        }
        return "pie_chart_option.ftl";
    }


    /***
     * 将html中预留的echars图片埋点全部替换成图片base64，注意：html中的埋点为以下格式： <img data-id="id">  。id值可以使模型id，也可以是其他的唯一id，要和 echartOptions 参数中的 key 能对应上。
     * @入参: echartOptions echarts的option完整配置，已经装填好数据的那种，key为埋点<img data-id="id">的id的值
     * @入参: stringBuilder html字符串
     * @出参: 图片替换成base64后的html
     * @作者: 陈宏成
     * @日期: 2021/02/04
     */
    private StringBuilder replaceEchartImgForHtml(Map<String,String> echartOptions, StringBuilder stringBuilder){
        if (echartOptions.isEmpty()){
            return stringBuilder;
        }
        echartOptions.entrySet().parallelStream().forEach(entry->{
            String modelId = entry.getKey();
            String option = entry.getValue();
            String base64Str = null;
            try {
                String eChartPath = EchartGenerateUtil.generateEChart(option);
                base64Str = ByteToFileUtils.encodeBase64File(eChartPath);
                //删除文件
                FileUtil.deleteFile(eChartPath);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 如果图片存在，替换html埋点
                String imgHtml = "";
                if (StringUtils.hasText(base64Str)){
                    imgHtml = "<img style=\"text-align:center;display:table-cell\" src=\"data:image/png;base64," + base64Str + "\">";
                }
                String imgBuriedPointStr  = "<img data-id=\"" + modelId + "\">";
                synchronized (stringBuilder){
                    int imgIndexStart = stringBuilder.indexOf(imgBuriedPointStr);
                    int imgIndexend = imgIndexStart + imgBuriedPointStr.length();
                    stringBuilder.replace(imgIndexStart,imgIndexend,imgHtml);
                }
            }
        });
        return stringBuilder;
    }



    /***
     * @描述: 从模型结果的json对象中获取一个地区的数据，包括处理子级的数据。循环调用getOneDataFromJson
     * @入参: modelResultJson 模型结果json字符串
     * @入参: divisionCode 行政区划编码，用于查询json中那个部分的数据
     * @入参: hasChildren 返回结果是否包含指定行政区划的直接子行政区划数据
     * @入参: hasChildren 是否同时查询子行政区的数据
     * @出参: [{"divisionCode":"4412","divisionText":"鹤壁市","total_value":"总量，不一定有，看模型结果具体内容","unit":"单位，不一定有，看模型结果具体内容","items":[{"key":"占现状耕地面积比例","value":"123","count":"123","unit":"公顷"},{"key":"现状耕地面积","value":"123","count":"123","unit":"公顷"}]}]
     * @see MdlModelExportServiceImpl#getOneDivisionDataFromModelResult0(JSONObject)
     * @作者: 陈宏成
     * @日期: 2021/02/02
     */
    private List<Map<String,Object>> getOneDivisionDataFromModelResult(String modelResultJson,String divisionCode, boolean hasChildren){
        MapDivision division = iMapClient.mateByCode(divisionCode);
        String divisionText = division == null ? "" : division.getName();

        if (!StringUtils.hasText(modelResultJson)){
            return new LinkedList<>();
        }
        LinkedHashMap<String, Object> jsonMap = JSON.parseObject(modelResultJson, LinkedHashMap.class, Feature.OrderedField);
        JSONObject rootGroupItem = (JSONObject)jsonMap.get(ModelConst.MODEL_LEVEL_ROOTGROUPITEM);
        if (rootGroupItem == null){
            return new LinkedList<>();
        }
        // 获取该模型指定区域的结果数据
        JSONObject divisionResult = this.findDivisionResult(rootGroupItem, divisionCode,divisionText);
        // 如果没有结果，直接返回空
        if(divisionResult == null){
            return new LinkedList<>();
        }
        // 解析json数据
        List<Map<String, Object>> dataList = new LinkedList<>();
        Map<String, Object> data1 = this.getOneDivisionDataFromModelResult0(divisionResult);
        if (data1 != null ){
            dataList.add(data1);
        }
        if(hasChildren){
            // 获取子项的
            if (divisionResult.containsKey(ModelConst.MODEL_LEVEL_SUBLEVEL1GROUPITEM)){
                JSONArray jsonArray = divisionResult.getJSONArray(ModelConst.MODEL_LEVEL_SUBLEVEL1GROUPITEM);
                for(int i1 = 0; i1 < jsonArray.size(); i1++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(i1);
                    Map<String, Object> data = this.getOneDivisionDataFromModelResult0(jsonObject);
                    if(data != null){
                        dataList.add(data);
                    }
                }
            }
        }
        return dataList;
    }

    /***
     * @描述: 从模型结果的json对象中获取一个地区的数据，不处理子级的数据
     * @入参: jsonObject 从模型结果的json对象，是一个SubLevel1GroupItems的子元素，例如：{"GroupItemCode":"41","GroupItemName":"河南省","GroupItemLevelName":"行政区","StatisticInformation":{"Current":{"$合计$":{"Area_Value":"245.872999074661","Area_Unit":"公顷","Count":"14427"},"冲突面积":{"Area_Value":"32.56","Area_Unit":"公顷","Count":"552"},"现状耕地面积":{"Area_Value":"65.99","Area_Unit":"公顷","Count":"74"},"占现状耕地面积比例":{"Area_Value":"49.34","Area_Unit":"%","Count":"74"}}}}
     * @出参: map对象，{"divisionCode":"4412","divisionText":"鹤壁市","total_value":"245.872999074661","unit":"公顷","items":[{"key":"占现状耕地面积比例","value":"123","count":"123","unit":"公顷"},{"key":"现状耕地面积","value":"123","count":"123","unit":"公顷"}]}
     * @作者: 陈宏成
     * @日期: 2021/02/02
     */
    private Map<String,Object> getOneDivisionDataFromModelResult0(JSONObject jsonObject){
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("divisionText",jsonObject.getString(ModelConst.MODEL_FEATURE_DIVISION_GROUPITEMNAME));
        dataMap.put("divisionCode",jsonObject.getString(ModelConst.MODEL_FEATURE_DIVISION_GROUPITEMCODE));
        JSONObject statisticInformation = jsonObject.getJSONObject(ModelConst.MODEL_STATISTICAL_STATISTICINFORMATION);
        if(statisticInformation == null || statisticInformation.isEmpty()){
            return null;
        }
        JSONObject current = statisticInformation.getJSONObject(ModelConst.MODEL_VALUE_TYPE_CURRENT);
        if (current == null){
            current = statisticInformation.getJSONObject(ModelConst.MODEL_VALUE_TYPE_PLAN);
        }
        if (current == null){
            current = statisticInformation.getJSONObject(ModelConst.MODEL_VALUE_TYPE_TREND);
        }
        if (current == null){
            // Warn 预警值类型是特殊的
            JSONArray jsonArray = statisticInformation.getJSONArray(ModelConst.MODEL_VALUE_TYPE_WARN);
            List<Map<String, String>> items = new LinkedList<>();
            for(int i = 0; i < jsonArray.size(); i++) {
                Map<String, String> stringStringHashMap = new HashMap<>();
                JSONObject jsonObject1 = jsonArray.getJSONObject(i);
                stringStringHashMap.put("key" ,jsonObject1.getString("Name"));
                stringStringHashMap.put("value" ,jsonObject1.getString("Area"));
                stringStringHashMap.put("percent" ,jsonObject1.getString("Percent"));
                items.add(stringStringHashMap);
            }
            dataMap.put("items",items);
            return dataMap;
        }
        // 总计
        JSONObject totalJsonObject = current.getJSONObject(ModelConst.MODEL_FEATURE_FIELD_TOTAL);
        dataMap.put("unit",totalJsonObject.getString("Area_Unit"));
        dataMap.put("total_value",totalJsonObject.getString("Area_Value"));
        if (totalJsonObject.containsKey("Area_Value")){
            dataMap.put("Area_Value",CommonUtil.formatNumber(totalJsonObject.getString("Area_Value"),2));
        }else{
            dataMap.put("Area_Value",null);
        }
        dataMap.put("Area_Unit",totalJsonObject.getString("Area_Unit"));
        if (totalJsonObject.containsKey("OtherArea_Value")){
            dataMap.put("OtherArea_Value",CommonUtil.formatNumber(totalJsonObject.getString("OtherArea_Value"),2));
        }else{
            dataMap.put("OtherArea_Value",null);
        }
        dataMap.put("OtherArea_Unit",totalJsonObject.getString("OtherArea_Unit"));
        int i = 1;
        List<Map<String, String>> items = new LinkedList<>();
        for(String key : current.keySet()) {
            Map<String, String> stringStringHashMap = new HashMap<>();
            if (ModelConst.MODEL_FEATURE_FIELD_TOTAL.equals(key)){
                continue;
            }else{
                stringStringHashMap.put("key" ,key);
            }
            String area_value = current.getJSONObject(key).getString("Area_Value");
            if (StringUtils.hasText(area_value)){
                stringStringHashMap.put("value" ,CommonUtil.formatNumber(area_value,2, null));
            }else{
                stringStringHashMap.put("value" ,null);
            }
            stringStringHashMap.put("unit" ,current.getJSONObject(key).getString("Area_Unit"));
            stringStringHashMap.put("count"  ,current.getJSONObject(key).getString("Count"));
            items.add(stringStringHashMap);
            i++;
        }
        dataMap.put("items",items);
        return dataMap;
    }


    /**
     * @描述: 在模型结果的json对象中查找对应地区的json对象
     * @入参: jsonObject  模型结果的json对象 ，必填
     * @入参: divisionCode 行政区域编码
     * @入参: divisionText 行政区域中文名
     * @出参: 该区域对应地区的json对象
     * @作者: 陈宏成
     * @日期: 2021/02/02
     */
    private JSONObject findDivisionResult(JSONObject jsonObject, String divisionCode,String divisionText){
        // 如果行政区域相等，直接返回
        if ((StringUtils.hasText(jsonObject.getString(ModelConst.MODEL_FEATURE_DIVISION_GROUPITEMCODE)) && jsonObject.getString(ModelConst.MODEL_FEATURE_DIVISION_GROUPITEMCODE).equals(divisionCode))
            || StringUtils.hasText(jsonObject.getString(ModelConst.MODEL_FEATURE_DIVISION_GROUPITEMNAME)) && jsonObject.getString(ModelConst.MODEL_FEATURE_DIVISION_GROUPITEMNAME).equals(divisionText)) {
            return jsonObject;
        }
        // 否则就查他的子节点
        JSONArray subLevel1GroupItems = jsonObject.getJSONArray(ModelConst.MODEL_LEVEL_SUBLEVEL1GROUPITEM);
        if (subLevel1GroupItems == null || subLevel1GroupItems.isEmpty()) {
            return null;
        }
        for(int i = 0; i < subLevel1GroupItems.size(); i++) {
            JSONObject childJsonObject = subLevel1GroupItems.getJSONObject(i);
            JSONObject result = this.findDivisionResult(childJsonObject, divisionCode,divisionText);
            if (result != null){
                return result;
            }
        }
        return null;
    }


    /**
     * 对模型目录树列表进行排序，排序结果按照原来树的结构顺序
     * @入参: originalList 原模型目录树列表
     * @入参: parentDirId 父目录id
     * @入参: resultList 结果列表
     * @入参: lastModelDir 上一个模型目录对象，用于计算下一层级的层数
     * @作者: 陈宏成
     * @日期: 2021/02/02
     */
    private void sortList(List<ApiMdlModelDir> originalList, String parentDirId, List<ApiMdlModelDir> resultList, ApiMdlModelDir lastModelDir) {
        for (ApiMdlModelDir node :originalList) {
            if (node.getParentId().equals(parentDirId)) {
                if (lastModelDir != null && lastModelDir.getTreeLevel() != null) {
                    node.setTreeLevel(lastModelDir.getTreeLevel() + 1);
                } else {
                    node.setTreeLevel(node.getTreeLevel() + 1);
                }
                resultList.add(node);
                sortList(originalList,node.getId(),resultList,node);
            }
        }
    }


    /**
     * 根据模型体系编码，查询模型目录及模型结果
     * @入参: modelTypeCode  模型体系编码，必填
     * @入参: keyWord 关键字，可以不填，如果填写了，就根据模型名进行过滤
     * @入参: year 模型结果的年份，如果不填，则不返回模型结果
     * @入参: isReturnTree 是否返回树形结构，true - 返回树形结构，false - 返回列表结构，但是顺序还是树形结构的顺序
     * @出参: 模型目录列表
     * @作者: 陈宏成
     * @日期: 2021/02/04 9:33
     */
    private List<ApiMdlModelDir> listModelDirs(String modelTypeCode, String keyWord, String year, boolean isReturnTree){
        // 查询模型体系
        LambdaQueryWrapper<MdlModelType> lambda = new QueryWrapper().lambda();
        lambda.eq(MdlModelType::getCode,modelTypeCode);
        MdlModelType one = mdlModelTypeService.getOne(lambda);
        // 查询模型
        List<ApiMdlModelDir> mdlModelDirs = one == null? new LinkedList<>(): mdlModelDirService.listTreeByEntity(one.getId(), null);
        // 查询对应的模型
        mdlModelDirs.parallelStream().forEach(mdl -> {
            if (mdl.getType() == 2){
                LambdaQueryWrapper<MdlModel> lambda2 = new QueryWrapper().lambda();
                lambda2.eq(MdlModel::getId,mdl.getModelId());
                //config字段太大 不返回
                lambda2.select(MdlModel::getId,MdlModel::getName,MdlModel::getType,MdlModel::getUseCount,MdlModel::getDescription,MdlModel::getSampleLayerUrl,MdlModel::getCalculate,MdlModel::getIntroduce,MdlModel::getLevelStandard,MdlModel::getCalculateProcess,MdlModel::getResultLayer,MdlModel::getCreator,MdlModel::getCreateTime,MdlModel::getModifier,MdlModel::getModifyTime);
                mdl.setMdlModel(mdlModelService.getOne(lambda2));
            }
        });
        if (StringUtils.hasText(keyWord)){
            // 根据关键字进行过滤
            mdlModelDirs = mdlModelDirs.stream().filter(dir -> {
                if (dir.getType() == 1) {
                    return true;
                }
                return dir.getType() == 2 && dir.getMdlModel() != null && dir.getMdlModel().getName().contains(keyWord);
            }).collect(Collectors.toList());
        }
        if(StringUtils.hasText(year)){
            // 查询对应的模型结果
            mdlModelDirs.parallelStream().forEach(mdl -> {
                if (mdl.getType() == 2){
                    LambdaQueryWrapper<MdlModelResult> lambda1 = new QueryWrapper().lambda();
                    lambda1.eq(MdlModelResult::getYear,year);
                    lambda1.like(MdlModelResult::getModelIds,mdl.getModelId());
                    List<MdlModelResult> modelResultList = mdlModelResultService.list(lambda1);
                    if (modelResultList != null && !modelResultList.isEmpty()){
                        mdl.setMdlModelResult(modelResultList.get(0));
                    }
                }
            });
        }
        if (isReturnTree){
            // 将列表转成一棵树
            mdlModelDirs = RecursionUtils.buildModelDirTree2(mdlModelDirs,one == null? "0": one.getId());
        }else {
            List<ApiMdlModelDir> apiMdlModelDirs = new ArrayList<>(mdlModelDirs.size());
            this.sortList(mdlModelDirs,one.getId(),apiMdlModelDirs,null);
            mdlModelDirs = apiMdlModelDirs;
        }
        return mdlModelDirs;
    }


    /***
     * 通过调用NewWordUtil.wordprint方法来生成一个word文档，并存放在临时文件夹中
     * @入参: templateName 模板文件名字，模板文件需放在resources/template/目录中
     * @入参: fieldMap 普通文档域字段map，key为域名，value为域值
     * @入参: tableName word文档中可以有一个表格，这里填表格的域名，例如ZBMX，具体看自己的模板
     * @入参: tableDataList word文档中可以有一个表格，这里填写表格的数据
     * @入参: mergeTableCellList word文档中可以有一个表格，这里填写表格中要合并的单元格配置。key为"rowCell"，value为 "rowStart,colStart,rowEnd,colEnd"
     * @入参: htmlStr 要渲染的html内容
     * @出参: 在本地临时文件夹中创建的模板的文件名
     * @throws Exception
     * @作者: 陈宏成
     * @日期: 2021/02/02
     */
    private String createWord( String templateName, Map<String, Object> fieldMap, String tableName, List<Map<String, Object>> tableDataList
            ,List<Map<String, String>> mergeTableCellList,String htmlStr) throws Exception {
        // 文档域字段
        List<Map<String, Object>> fieldData = new ArrayList<>(2);
        HashMap<String, Object> docFieldMap = new HashMap<>();
        HashMap<String, Object> docHtmlFieldMap = new HashMap<>();
        fieldData.add(docFieldMap);
        fieldData.add(docHtmlFieldMap);
        if(fieldMap != null){
            // 普通文档域字段
            ArrayList<Object> fieldList = new ArrayList<>();
            fieldList.add(fieldMap);
            docFieldMap.put("table",fieldList);
        }
        // 文档表格字段
        List<Map<String, Object>> tableData = new ArrayList<>();
        if(StringUtils.hasText(tableName) && tableDataList != null && !tableDataList.isEmpty()){
            HashMap<String, Object> tableDataMap = new HashMap<>();
            tableData.add(tableDataMap);
            tableDataMap.put("name",tableName);
            tableDataMap.put("table",tableDataList);
        }
        // 整理合并单元格数据
        List<Map<String, Object>> mergeTableList = new ArrayList<>(1);
        if(mergeTableCellList != null && !mergeTableCellList.isEmpty()){
            HashMap<String, Object> mergeTableMap = new HashMap<>(2);
            mergeTableList.add(mergeTableMap);
            mergeTableMap.put("xh",0);
            mergeTableMap.put("cells",mergeTableCellList);
        }
        if(StringUtils.hasText(htmlStr)){
            // html域字段
            docHtmlFieldMap.put("type","html");
            ArrayList<HashMap<String, Object>> htmlList = new ArrayList<>();
            docHtmlFieldMap.put("table",htmlList);
            HashMap<String, Object> htmlMap = new HashMap<>();
            htmlList.add(htmlMap);
            htmlMap.put("html_str",htmlStr);
        }

        ClassPathResource resource = new ClassPathResource("template/" + templateName);
        InputStream inputStream = resource.getInputStream();
        //进行word打印
        String docx = NewWordUtil.wordprint(inputStream, fieldData, tableData, null, "docx", "", "", mergeTableList);
        inputStream.close();
        return docx.substring(docx.lastIndexOf("/") + 1, docx.length());
    }


    /**
     * @描述: 保留两位小数
     * @入参: value 原字符串
     * @出参: 如果value为空，返回空字符串，否则保留两位小数
     * @作者: 陈宏成
     * @日期: 2021/02/04
     **/
    private String holdTwoDecimal(String value){
        if(!StringUtils.hasText(value)){
            return "";
        }
        return ConvertUtil.formatNumber(Double.valueOf(value), 2);
    }

    /**
     * @描述: 获取标题编号字符串，如果titleIndex=2，层级level=1，返回：二、；如果层级level=2，返回：（2）.；如果层级level>=3，返回：3、
     * @入参: level 层级
     * @入参: titleIndex 标题序号
     * @出参: 如果titleIndex=2，层级level=1，返回：二、；如果层级level=2，返回：（2）.；如果层级level=3，返回：3、
     * @作者: 陈宏成
     * @日期: 2021/02/04
     **/
    private String getTitleIndexStr(int level,int titleIndex){
        String titleIndexStr = "";
        if (level == 1){
            titleIndexStr = ConvertUtil.ToCH(titleIndex) + "、";
        }else if(level == 3){
            titleIndexStr = "（"+titleIndex+"）. ";
        }else{
            titleIndexStr = titleIndex+"、";
        }
        return titleIndexStr;
    }
}
